<?php
/**
 * Cola_Template 简单模板解析引擎
 * 
 * @package colaphp
 * @author sasou
 * @copyright 2015
 * @version 1.0
 * @access public
 */
class Cola_Template
{
    /**
     * 变量储存的数组
     *
     * @var string
     */
	private $vars = array();
    /**
     * 模板文件后缀
     *
     * @var string
     */
    public $tplExt = '.htm';
    /**
     * 模板目录
     *
     * @var string
     */
	public $templateDir = '';
    /**
     * 编译目录
     *
     * @var string
     */
	public $templateComplieDir = './AppData/template_c/';
    /**
     * 模板文件
     *
     * @var string
     */
	public $templateFile = '';
    /**
     * 左连接符
     *
     * @var string
     */
	public $leftDelimiter = '<{';
    /**
     * 右连接符
     *
     * @var string
     */
	public $rightDelimiter = '}>';
    /**
     * 编译文件
     *
     * @var string
     */
	private $templateComplieFile = '';
    /**
     * 缓存时间
     *
     * @var string
     */
	public $cacheTime = 0;
    /**
     * 是否开启编译
     *
     * @var string
     */
    public $isComplie = false;
	
	/**
	 * 构造器
	 */
	public function __construct(){
		if(defined('APP_ROOT')){
			$this->templateComplieDir = APP_ROOT . 'AppData/template_c/';
		}
		$arr = Cola::getConfig('_template');
		if(is_array($arr)){
			isset($arr ['left']) && $arr ['left']!="" && $this->leftDelimiter = $arr ['left'];
			isset($arr ['right']) && $arr ['right']!="" && $this->rightDelimiter = $arr ['right'];
			isset($arr ['cacheTime']) && $this->cacheTime = $arr ['cacheTime'];
			isset($arr ['isComplie']) && $this->isComplie = $arr ['isComplie'];
		}
	}
	
	/**
	 * 变量赋值
	 * @param $key mixed 键名
	 * @param $value mixed 值
	 */
	public function assign($key , $value = ''){
		if(is_array($key)){
			$this->vars=array_merge($key,$this->vars);
		}
		else{
			$this->vars[$key]=$value;
		}
	}
	
	/**
	 * 显示页面
	 * @param $parentTpl string 父模板文件名
     * @param $file string 模板文件名
	 */
	public function display($parentTpl,$file){
	    if($parentTpl!=''){
			$parentTpl = APP_ROOT.Cola::getConfig('_viewsHome').DIRECTORY_SEPARATOR.$parentTpl.$this->tplExt;
			$this->assign("childTpl",$file);
			echo $this->fetch($parentTpl);
		}else{
			$file = APP_ROOT.Cola::getConfig('_viewsHome').DIRECTORY_SEPARATOR.$file.$this->tplExt;
			echo $this->fetch($file);
		}
	}
	
	/**
	 * 返回缓存区内容
	 * @param $file string 模板文件名
	 * @return $content string 缓存内容
	 */
	public function fetch($file){
		$this->templateFile = $this->templateDir .$file;
		$this->templateComplieFile = md5($this->templateFile) . '.php';
        if($this->isComplie){
    		$templateComplieFile_time = 0;
    		if(file_exists($this->templateComplieDir . $this->templateComplieFile)){
    			$templateComplieFile_time = filemtime($this->templateComplieDir . $this->templateComplieFile);
    		}
    		//若在超过缓存时间，则编译
    		if($this->cacheTime < time()-$templateComplieFile_time){
    			$desc_content = $this->readfile($this->templateFile);
    			$this->complie($this->initTwo($desc_content));
    		}
        }
		//以下获取缓存区的内容
		ob_start();
		@extract($this->vars , EXTR_OVERWRITE);
		include ($this->templateComplieDir . $this->templateComplieFile);
		$content = ob_get_contents();
		ob_end_clean();
		
		//$this->store_buff($content);
		return $content;
	}
	
	/**
	 * 替换分隔符，以及替换解析器的内容
	 * @param $content string 读取的内容
	 * @return $content string 替换后的内容
	 */
	public function initTwo($content){
		//内置解析器
		$preg_temp = array(
			'~<\{(\$[a-z0-9_]+)\}>~i'
				=> '<?php if(isset($1))echo $1; ?>', // <{$name}>
			
			'~<\{(\$[a-z0-9_]+)\.([a-z0-9_]+)\}>~i'
				=> '<?php echo $1[\'$2\']; ?>', // <{$arr.key}>
			
			'~<\{(\$[a-z0-9_]+)\.([a-z0-9_]+)\.([a-z0-9_]+)\}>~i'
				=> '<?php echo $1[\'$2\'][\'$3\']; ?>', // <{$arr.key.key2}>
			
			'~<\{(include_once|require_once|include|require|layout)\s*\(\s*(.+?)\s*\)\s*\}>~i'
				=> '<?php \$this->layout($2); ?>', // ＜?php include('inc/top.php'); ?＞
			
			'~<\{:(.+?)\}>~' => '<?php echo $1; ?>', // <{:strip_tags($a)}>
			
			'~<\{\~(.+?)\}>~' => '<?php $1; ?>', // <{~var_dump($a)}>
			
			'~<\?=\s*~' => '<?php echo ', // <?=
		);
		if($this->leftDelimiter != '<{'){
			$pattern = array('/'.$this->leftDelimiter.'/', '/'.$this->rightDelimiter.'/');
			$replacement = array('<{', '}>');
			$content = preg_replace($pattern, $replacement, $content);
		}
		$content = preg_replace(array_keys($preg_temp), $preg_temp , $content);
		$content = $this->init($content,'<{' ,'}>' );
		return $content;
	}
	
	/**
	 * 模板驱动-简单的驱动
	 * @param  string $str 模板文件数据
	 * @return string
	 */
	 public function init($str, $left, $right) {
		//子模板
		$str = preg_replace( "/".$left."childTpl".$right."/", '<?php \$this->layout($childTpl);?>', $str );
	 	//if操作
	 	$str = preg_replace( "/".$left."if([^{]+?)".$right."/", "<?php if \\1 { ?>", $str );
		$str = preg_replace( "/".$left."else".$right."/", "<?php } else { ?>", $str );
		$str = preg_replace( "/".$left."elseif([^{]+?)".$right."/", "<?php } elseif \\1 { ?>", $str );
		//foreach操作
		$str = preg_replace("/".$left."foreach([^{]+?)".$right."/","<?php foreach \\1 { ?>",$str);
		$str = preg_replace("/".$left."\/foreach".$right."/","<?php } ?>",$str);
		//for操作
		$str = preg_replace("/".$left."for([^{]+?)".$right."/","<?php for \\1 { ?>",$str);
		$str = preg_replace("/".$left."\/for".$right."/","<?php } ?>",$str);
		//输出变量
		$str = preg_replace( "/".$left."(\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_$\x7f-\xff\[\]\'\']*)".$right."/", "<?php if(isset(\\1)) echo \\1;?>", $str );
		//常量输出
		$str = preg_replace( "/".$left."([A-Z_\x7f-\xff][A-Z0-9_\x7f-\xff]*)".$right."/s", "<?php echo \\1;?>", $str );
		//标签解析
		$str = preg_replace ( "/".$left."\/if".$right."/", "<?php } ?>", $str );
	 	$pattern = array('/'.$left.'/', '/'.$right.'/');
		$replacement = array('<?php ', ' ?>');
		return preg_replace($pattern, $replacement, $str);
	 }
	
	/**
	 * 编译储存
	 * @param $content string 读取的内容
	 *
	 */
	public function complie($content){
		$this->templateComplieFile = md5($this->templateFile) . '.php';
		$tempfile = $this->templateComplieDir . $this->templateComplieFile;
		$fp = fopen($tempfile , 'w');
		fputs($fp,$content);
		fclose($fp);
		unset($fp);
	}
	
	/**
	 * 读取文件的内容
	 * @param $file string 文件名
	 * @return $content string 文件内容
	 */
	public function readfile($file){
		if(file_exists($file)){
			$fp = fopen($file , 'r');
			$content ='';
			while(!feof($fp)){
				$content .= fgets($fp,4096);
			}
			fclose($fp);
			unset($fp);
			return $content;
		}
		else{
			exit($file . ' not exist!');
		}
	}
	
	/**
	 * 模板嵌套
	 * @param $file string 文件名
	 * @return 
	 */
	public function layout($file){
		$file = APP_ROOT.Cola::getConfig('_viewsHome').DIRECTORY_SEPARATOR.$file.$this->tplExt;
		if(file_exists($file)){
			echo $this->fetch($file);
		}
		else{
			echo "模板文件不存在";
			exit;
		}
	}
	
	/**
	 * 访问控制器
	 * @param $c string 控制器
	 * @param $a string 操作
	 * @param $params array 参数
	 * @return
	 */
	public function controller($c,$a,$params = null){
		if(!class_exists($c, false)){
			$file = APP_ROOT.str_replace('_',DIRECTORY_SEPARATOR,$c) . '.php';
			if (file_exists($file)) {
				include $file;
			}
		}
		$controller = new $c();
		if(is_array($params)){
			$_REQUEST_BAK = $_REQUEST;
			$_REQUEST = $params;
		}
		if (method_exists($controller, $a)) {
			call_user_func(array($controller, $a));
		}
		isset($_REQUEST_BAK) && $_REQUEST = $_REQUEST_BAK;
	}
}